home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / wais / waisgate / HTWAIS.c < prev    next >
C/C++ Source or Header  |  1995-05-09  |  22KB  |  835 lines

  1. /*    WorldWideWeb - Wide Area Informaion Server Access    HTWAIS.c
  2. **    ==================================================
  3. **
  4. **    This module allows a WWW server or client to read data from a
  5. **    remote  WAIS
  6. **  server, and provide that data to a WWW client in hypertext form.
  7. **  Source files, once retrieved, are stored and used to provide
  8. **  information about the index when that is acessed.
  9. **
  10. ** Authors
  11. **    BK    Brewster Kahle, Thinking Machines, <Brewster@think.com>
  12. **    TBL    Tim Berners-Lee, CERN <timbl@info.cern.ch>
  13. **
  14. ** History
  15. **       Sep 91    TBL adapted shell-ui.c (BK) with HTRetrieve.c from WWW.
  16. **       Feb 91    TBL Generated HTML cleaned up a bit (quotes, escaping)
  17. **                Refers to lists of sources. 
  18. **       Mar 93    TBL   Lib 2.0 compatible module made.    
  19. **
  20. ** Bugs
  21. **    Uses C stream i/o to read and write sockets, which won't work
  22. **    on VMS TCP systems.
  23. **
  24. **    Should cache connections.
  25. **
  26. **    ANSI C only as written
  27. **
  28. ** WAIS comments:
  29. **
  30. **    1.    Separate directories for different system's .o would help
  31. **    2.    Document ids are rather long!
  32. **
  33. ** WWW Address mapping convention:
  34. **
  35. **    /servername/database/type/length/document-id
  36. **
  37. **    /servername/database?word+word+word
  38. */
  39. /* WIDE AREA INFORMATION SERVER SOFTWARE:
  40.    No guarantees or restrictions.  See the readme file for the full standard
  41.    disclaimer.
  42.  
  43.    Brewster@think.com
  44. */
  45.  
  46.  
  47. #define DIRECTORY "/quake.think.com:210/directory-of-servers"
  48.  
  49. #define BIG 1024    /* identifier size limit  @@@@@ */
  50.  
  51. /*            From WAIS
  52. **            ---------
  53. */
  54. #include "ui.h"
  55.  
  56.  
  57. #define MAX_MESSAGE_LEN 100000
  58. #define CHARS_PER_PAGE 10000 /* number of chars retrieved in each request */
  59.  
  60. #define WAISSEARCH_DATE "Fri Jul 19 1991"
  61.  
  62.  
  63. /*            FROM WWW
  64. **            --------
  65. */
  66. #define BUFFER_SIZE 4096    /* Arbitrary size for efficiency */
  67.  
  68. #define HEX_ESCAPE '%'
  69.  
  70. #include "HTUtils.h"
  71. #include "tcp.h"
  72. #include "HTParse.h"
  73. #include "HTAccess.h"        /* We implement a protocol */
  74. #include "HTML.h"        /* The object we will generate */
  75.  
  76. /* #include "ParseWSRC.h" */
  77.  
  78. extern int WWW_TraceFlag;    /* Control diagnostic output */
  79. extern FILE * logfile;        /* Log file output */
  80.  
  81. PRIVATE BOOL    as_gate;    /* Client is using us as gateway */
  82.  
  83. PRIVATE char    line[2048];    /* For building strings to display */
  84.                 /* Must be able to take id */
  85.  
  86.  
  87. #include "HTParse.h"
  88. #include "HTFormat.h"
  89. #include "HTTCP.h"
  90. /* #include "HTWSRC.h"    */    /* Need some bits from here */
  91.  
  92. /*        Hypertext object building machinery
  93. */
  94. #include "HTML.h"
  95.  
  96. #define PUTC(c) (*target->isa->put_character)(target, c)
  97. #define PUTS(s) (*target->isa->put_string)(target, s)
  98. #define START(e) (*target->isa->start_element)(target, e, 0, 0)
  99. #define END(e) (*target->isa->end_element)(target, e)
  100. #define END_TARGET (*target->isa->end_document)(target)
  101. #define FREE_TARGET (*target->isa->free)(target)
  102.  
  103. struct _HTStructured {
  104.     CONST HTStructuredClass *    isa;
  105.     /* ... */
  106. };
  107.  
  108. struct _HTStream {
  109.     CONST HTStreamClass *    isa;
  110.     /* ... */
  111. };
  112.  
  113.  
  114. /*                                showDiags
  115. */
  116. /* modified from Jonny G's version in ui/question.c */
  117. void showDiags ARGS2(
  118.     HTStream *,         target,
  119.     diagnosticRecord **,     d)
  120. {
  121.   long i;
  122.  
  123.   for (i = 0; d[i] != NULL; i++) {
  124.     if (d[i]->ADDINFO != NULL) {
  125.       PUTS("Diagnostic code is ");
  126.       PUTS(d[i]->DIAG);
  127.       PUTC(' ');
  128.       PUTS(d[i]->ADDINFO);
  129.       PUTC('\n'); ;
  130.     }
  131.   }
  132. }
  133.  
  134. /*    Matrix of allowed characters in filenames
  135. **    -----------------------------------------
  136. */
  137.  
  138. PRIVATE BOOL acceptable[256];
  139. PRIVATE BOOL acceptable_inited = NO;
  140.  
  141. PRIVATE void init_acceptable NOARGS
  142. {
  143.     unsigned int i;
  144.     char * good = 
  145.       "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./-_$";
  146.     for(i=0; i<256; i++) acceptable[i] = NO;
  147.     for(;*good; good++) acceptable[(unsigned int)*good] = YES;
  148.     acceptable_inited = YES;
  149. }
  150.  
  151. /*    Transform file identifier into WWW address
  152. **    ------------------------------------------
  153. **
  154. **
  155. ** On exit,
  156. **    returns        nil if error
  157. **            pointer to malloced string (must be freed) if ok
  158. */
  159. char * WWW_from_archie ARGS1 (char *, file)
  160. {
  161.     char * end;
  162.     char * result;
  163.     char * colon;
  164.     for(end=file; *end > ' '; end++);    /* assumes ASCII encoding*/
  165.     result = (char *)malloc(10 + (end-file));
  166.     if (!result) return result;        /* Malloc error */
  167.     strcpy(result, "file://");
  168.     strncat(result, file, end-file);
  169.     colon = strchr(result+7, ':');    /* Expect colon after host */
  170.     if (colon) {
  171.     for(; colon[0]; colon[0]=colon[1], colon++);    /* move down */
  172.     }
  173.     return result;
  174. } /* WWW_from_archie */
  175.  
  176. /*    Transform document identifier into URL
  177. **    --------------------------------------
  178. **
  179. ** Bugs: A static buffer of finite size is used!
  180. **    The format of the docid MUST be good!
  181. **
  182. ** On exit,
  183. **    returns        nil if error
  184. **            pointer to malloced string (must be freed) if ok
  185. */
  186. PRIVATE char hex [16] = "0123456789ABCDEF";
  187. extern char from_hex PARAMS((char a));            /* In HTWSRC @@ */
  188.  
  189. char * WWW_from_WAIS ARGS1(any *, docid)
  190.  
  191. {
  192.     static char buf[BIG];
  193.     char * q = buf;
  194.     char * p = (docid->bytes);
  195.     int i, l;
  196.     if (TRACE) {
  197.     char *p;
  198.     fprintf(stderr, "WAIS id (%d bytes) is ", (int)docid->size);
  199.     for(p=docid->bytes; p<docid->bytes+docid->size; p++) {
  200.         if ((*p >= ' ') && (*p<= '~')) /* Assume ASCII! */
  201.         fprintf(stderr, "%c", *p);
  202.         else
  203.         fprintf(stderr, "<%x>", (unsigned)*p);
  204.     }
  205.     fprintf(stderr, "\n");
  206.     }     
  207.     for (p=docid->bytes; (p<docid->bytes+docid->size) && (q<&buf[BIG]);) {
  208.     if (TRACE) fprintf(stderr, "    Record type %d, length %d\n",
  209.         p[0], p[1]);
  210.         if (*p>10) {
  211.         fprintf(stderr, "Eh? DOCID record type of %d!\n", *p);
  212.         return 0;
  213.     }
  214.     {    /* Bug fix -- allow any byte value 15 Apr 93 */
  215.         unsigned int i = (unsigned) *p++;
  216.         
  217.         if (i > 99) {
  218.         *q++ = (i/100) + '0';
  219.         i = i % 100;
  220.         }
  221.         if (i > 9) {
  222.         *q++ = (i/10) + '0';
  223.         i = i % 10;
  224.         }
  225.         *q++ = i + '0';    /* Record type */
  226.     }
  227.     *q++ = '=';        /* Separate */
  228.     l = *p++;        /* Length */
  229.     for(i=0; i<l; i++, p++){
  230.         if (!acceptable[*p]) {
  231.         *q++ = HEX_ESCAPE;    /* Means hex commming */
  232.         *q++ = hex[(*p) >> 4];
  233.         *q++ = hex[(*p) & 15];
  234.         }
  235.         else *q++ = *p;
  236.     }
  237.     *q++= ';';        /* Terminate field */
  238.     }
  239.     *q++ = 0;            /* Terminate string */
  240.     if (TRACE) fprintf(stderr, "WWW form of id: %s\n", buf); 
  241.     {
  242.         char * result = (char *)malloc(strlen(buf)+1);
  243.     strcpy(result, buf);
  244.     return result;
  245.     }
  246. } /* WWW_from_WAIS */
  247.  
  248.  
  249. /*    Transform URL into WAIS document identifier
  250. **    -------------------------------------------
  251. **
  252. ** On entry,
  253. **    docname        points to valid name produced originally by
  254. **            WWW_from_WAIS
  255. ** On exit,
  256. **    docid->size    is valid
  257. **    docid->bytes    is malloced and must later be freed.
  258. */
  259. PRIVATE any * WAIS_from_WWW ARGS2 (any *, docid, char *, docname)
  260. {
  261.     char *z;     /* Output pointer */
  262.     char *sor;    /* Start of record - points to size field. */
  263.     char *p;     /* Input pointer */
  264.     char *q;     /* Poisition of "=" */
  265.     char *s;     /* Position of semicolon */
  266.     int n;    /* size */
  267.     if (TRACE) fprintf(stderr, "WWW id (to become WAIS id): %s\n", docname); 
  268.     for(n=0, p = docname; *p; p++) {    /* Count sizes of strings */
  269.         n++;
  270.     if (*p == ';')  n--;        /* Not converted */
  271.     else if (*p == HEX_ESCAPE) n=n-2;    /* Save two bytes */
  272.         docid->size = n;
  273.     }
  274.     
  275.     docid->bytes = (char *) malloc(docid->size); /* result record */
  276.     z = docid->bytes;
  277.     
  278.     for(p = docname; *p; ) {    /* Convert of strings */
  279.                     /* Record type */
  280.                 
  281.     *z = 0;            /* Initialize record type */
  282.     while (*p >= '0' && *p <= '9') {
  283.         *z = *z*10 + (*p++ - '0');    /* Decode decimal record type */
  284.     }
  285.     z++;
  286.     if (*p != '=') return 0;
  287.     q = p;
  288.     
  289. /*        *z++ = *p++ - '0';
  290.     q = strchr(p , '=');
  291.     if (!q) return 0;
  292. */
  293.     s = strchr(q, ';');    /* (Check only) */
  294.     if (!s) return 0;    /* Bad! No ';';    */
  295.         sor = z;        /* Remember where the size field was */
  296.     z++;            /* Skip record size for now    */
  297.     for(p=q+1; *p!=';' ; ) {
  298.        if (*p == HEX_ESCAPE) {
  299.             char c;
  300.         unsigned int b;
  301.         p++;
  302.             c = *p++;
  303.         b =   from_hex(c);
  304.         c = *p++;
  305.         if (!c) break;    /* Odd number of chars! */
  306.         *z++ = (b<<4) + from_hex(c);
  307.         } else {
  308.             *z++ = *p++;    /* Record */
  309.         }
  310.     }
  311.     *sor = (z-sor-1);    /* Fill in size -- not counting size itself */
  312.     p++;            /* After semicolon: start of next record */
  313.     }
  314.     
  315.     if (TRACE) {
  316.     char *p;
  317.     fprintf(stderr, "WAIS id (%d bytes) is ", (int)docid->size);
  318.     for(p=docid->bytes; p<docid->bytes+docid->size; p++) {
  319.         if ((*p >= ' ') && (*p<= '~')) /* Assume ASCII! */
  320.         fprintf(stderr, "%c", *p);
  321.         else
  322.         fprintf(stderr, "<%x>", (unsigned)*p);
  323.     }
  324.     fprintf(stderr, "\n");
  325.     }     
  326.     return docid;        /* Ok */
  327.     
  328. } /* WAIS_from_WWW */
  329.  
  330.  
  331. /*    Send a plain text record to the client        output_text_record()
  332. **    --------------------------------------
  333. */
  334.  
  335. PRIVATE void output_text_record ARGS3(
  336.     HTStream *,            target,
  337.     WAISDocumentText *,        record,
  338.     boolean,            quote_string_quotes)
  339. {
  340.   long count;
  341.   /* printf(" Text\n");
  342.      print_any("     DocumentID:  ", record->DocumentID);
  343.      printf("     VersionNumber:  %d\n", record->VersionNumber);
  344.      */
  345.   for(count = 0; count < record->DocumentText->size; count++){
  346.     long ch = (unsigned char)record->DocumentText->bytes[count];
  347.     if (ch == 27) {    /* What is this in for? Tim */
  348.  
  349.         /* then we have an escape code */
  350.         /* if the next letter is '(' or ')', then ignore two letters */
  351.         if('(' == record->DocumentText->bytes[count + 1] ||
  352.         ')' == record->DocumentText->bytes[count + 1])
  353.         count += 1;             /* it is a term marker */
  354.         else count += 4;        /* it is a paragraph marker */
  355.     } else if (ch == '\n' || ch == '\r') {
  356.         PUTC('\n');
  357.     } else if ((ch=='\t') || isprint(ch)){
  358.         PUTC(ch);
  359.     } 
  360.   }
  361. } /* output text record */
  362.  
  363.  
  364.  
  365. /*    Format A Search response for the client        display_search_response
  366. **    ---------------------------------------
  367. */
  368. /* modified from tracy shen's version in wutil.c
  369.  * displays either a text record or a set of headlines.
  370.  */
  371. void
  372. display_search_response ARGS4(
  373.     HTStructured *,        target,
  374.     SearchResponseAPDU *,    response,
  375.     char *,            database,
  376.     char *,             keywords)
  377. {
  378.   WAISSearchResponse  *info;
  379.   long i, k;
  380.   
  381.   BOOL archie =  strstr(database, "archie")!=0;    /* Specical handling */
  382.   
  383.   if (TRACE) fprintf(stderr, "WAISGate: Displaying search response\n");
  384.   sprintf(line,
  385.       "Index %s contains the following %d item%s relevant to '%s'.\n",
  386.      database,
  387.      (int)(response->NumberOfRecordsReturned),
  388.      response->NumberOfRecordsReturned ==1 ? "" : "s",
  389.      keywords);
  390.  
  391.   PUTS(line);
  392.   PUTS("The first figure for each entry is its relative score, ");
  393.   PUTS("the second the number of lines in the item.");
  394.   START(HTML_MENU);
  395.  
  396.   if ( response->DatabaseDiagnosticRecords != 0 ) {
  397.     info = (WAISSearchResponse *)response->DatabaseDiagnosticRecords;
  398.     i =0; 
  399.  
  400.     if (info->Diagnostics != NULL)
  401.       showDiags((HTStream*)target, info->Diagnostics);
  402.  
  403.     if ( info->DocHeaders != 0 ) {
  404.       for (k=0; info->DocHeaders[k] != 0; k++ ) {
  405.     WAISDocumentHeader* head = info->DocHeaders[k];
  406.     char * headline = trim_junk(head->Headline);
  407.     any * docid = head->DocumentID;
  408.     char * docname;            /* printable version of docid */
  409.     i++;
  410.  
  411. /*    Make a printable string out of the document id.
  412. */
  413.     if (TRACE) fprintf(stderr, 
  414.         "WAISGate:  %2ld: Score: %4ld, lines:%4ld '%s'\n", 
  415.            i,
  416.            (long int)(info->DocHeaders[k]->Score),
  417.            (long int)(info->DocHeaders[k]->Lines),
  418.            headline);
  419.  
  420.     START(HTML_LI);
  421.     sprintf(line, "%4ld  %4ld  ",
  422.         head->Score,
  423.         head->Lines);
  424.     PUTS( line);
  425.  
  426.     if (archie) {
  427.         char * www_name = WWW_from_archie(headline);
  428.         if (www_name) {
  429.         HTStartAnchor(target, NULL, www_name);
  430.         PUTS(headline);
  431.         
  432.         END(HTML_A);
  433.         free(www_name);
  434.         } else {
  435.          PUTS(headline);
  436.          PUTS(" (bad file name)");
  437.         }
  438.     } else { /* Not archie */
  439.         docname =  WWW_from_WAIS(docid);
  440.         if (docname) {
  441.         char * dbname = HTEscape(database, URL_XPALPHAS);
  442.         sprintf(line, "%s/%s/%d/%s",        /* W3 address */
  443.                     dbname,
  444.             head->Types ? head->Types[0] : "TEXT",
  445.             (int)(head->DocumentLength),
  446.             docname);
  447.         HTStartAnchor(target, NULL, line);
  448.         PUTS(headline);
  449.         END(HTML_A);
  450.         free(dbname);
  451.         free(docname);
  452.         } else {
  453.          PUTS("(bad doc id)");
  454.         }
  455.       }
  456.       } /* next document header */
  457.     } /* if there were any document headers */
  458.     
  459.     if ( info->ShortHeaders != 0 ) {
  460.       k =0;
  461.       while (info->ShortHeaders[k] != 0 ) {
  462.     i++;
  463.     PUTS( "(Short Header record, can't display)");
  464.       }
  465.     }
  466.     if ( info->LongHeaders != 0 ) {
  467.       k =0;
  468.       while (info->LongHeaders[k] != 0) {
  469.     i++;
  470.     PUTS( "\nLong Header record, can't display\n");
  471.       }
  472.     }
  473.     if ( info->Text != 0 ) {
  474.       k =0;
  475.       while (info->Text[k] != 0) {
  476.     i++;
  477.     PUTS( "\nText record\n");
  478.     output_text_record((HTStream*)target, info->Text[k++], false);
  479.       }
  480.     }
  481.     if ( info->Headlines != 0 ) {
  482.       k =0;
  483.       while (info->Headlines[k] != 0) {
  484.     i++;
  485.     PUTS( "\nHeadline record, can't display\n");
  486.     /* dsply_headline_record( info->Headlines[k++]); */
  487.       }
  488.     }
  489.     if ( info->Codes != 0 ) {
  490.       k =0;
  491.       while (info->Codes[k] != 0) {
  492.     i++;
  493.     PUTS( "\nCode record, can't display\n");
  494.     /* dsply_code_record( info->Codes[k++]); */
  495.       }
  496.     }
  497.   }                /* Loop: display user info */
  498.   END(HTML_MENU);
  499.   PUTC('\n'); ;
  500. }
  501.  
  502.  
  503.  
  504.  
  505. /*        Load by name                    HTLoadWAIS
  506. **        ============
  507. **
  508. **    This renders any object or search as required
  509. */
  510. PUBLIC int HTLoadWAIS ARGS4(
  511.     CONST char *,        arg,
  512.     HTParentAnchor *,    anAnchor,
  513.     HTFormat,        format_out,
  514.     HTStream*,        sink)
  515.  
  516. #define MAX_KEYWORDS_LENGTH 1000
  517. #define MAX_SERVER_LENGTH 1000
  518. #define MAX_DATABASE_LENGTH 1000
  519. #define MAX_SERVICE_LENGTH 1000
  520. #define MAXDOCS 40
  521.  
  522. {
  523.     static CONST char * error_header =
  524. "<h1>Access error</h1>\nThe WWW-WAIS gateway reports the following error:<P>\n";
  525.     char * key;              /* pointer to keywords in URL */
  526.     char* request_message = NULL; /* arbitrary message limit */
  527.     char* response_message = NULL; /* arbitrary message limit */
  528.     long request_buffer_length;    /* how of the request is left */
  529.     SearchResponseAPDU  *retrieval_response = 0;
  530.     char keywords[MAX_KEYWORDS_LENGTH + 1];
  531.     char *server_name;    
  532.     char *wais_database = NULL;        /* name of current database */
  533.     char *www_database;            /* Same name escaped */
  534.     char *service;
  535.     char *doctype;
  536.     char *doclength;
  537.     long document_length;
  538.     char *docname;
  539.     FILE *connection = 0;
  540.     char * names;        /* Copy of arg to be hacked up */
  541.     BOOL ok = NO;
  542.     
  543.     extern FILE * connect_to_server();
  544.     
  545.     if (!acceptable_inited) init_acceptable();
  546.     
  547.         
  548. /*    Decipher and check syntax of WWW address:
  549. **    ----------------------------------------
  550. **
  551. **    First we remove the "wais:" if it was spcified.  920110
  552. */  
  553.     names = HTParse(arg, "", PARSE_HOST | PARSE_PATH | PARSE_PUNCTUATION);
  554.     key = strchr(names, '?');
  555.     
  556.     if (key) {
  557.         char * p;
  558.     *key++ = 0;    /* Split off keywords */
  559.     for (p=key; *p; p++) if (*p == '+') *p = ' ';
  560.     HTUnEscape(key);
  561.     }
  562.     if (names[0]== '/') {
  563.     server_name = names+1;
  564.     if (as_gate =(*server_name == '/'))
  565.         server_name++;    /* Accept one or two */
  566.     www_database = strchr(server_name,'/');
  567.     if (www_database) {
  568.         *www_database++ = 0;        /* Separate database name */
  569.         doctype = strchr(www_database, '/');
  570.         if (key) ok = YES;    /* Don't need doc details */
  571.         else if (doctype) {    /* If not search parse doc details */
  572.         *doctype++ = 0;    /* Separate rest of doc address */
  573.         doclength = strchr(doctype, '/');
  574.         if(doclength) {
  575.             *doclength++ = 0;
  576.             document_length = atol(doclength);
  577.             if (document_length) {
  578.             docname=strchr(doclength, '/');
  579.             if (docname) {
  580.                 *docname++ = 0;
  581.                 ok = YES;    /* To avoid a goto! */
  582.             } /* if docname */
  583.             } /* if document_length valid */
  584.         } /* if doclength */
  585.         } else { /* no doctype?  Assume index required */
  586.             if (!key) key = "";
  587.         ok = YES;
  588.         } /* if doctype */
  589.     } /* if database */
  590.      }
  591.      
  592.      if (!ok)
  593.      return HTLoadError(sink, 500, "Syntax error in WAIS URL");
  594.  
  595.      if (TRACE) fprintf(stderr, "WAISGate: Parsed OK\n");
  596.      
  597.      service = strchr(names, ':');
  598.      if (service)  *service++ = 0;
  599.      else service = "210";
  600.      
  601.      if (server_name[0] == 0)
  602.         connection = NULL;
  603.  
  604.      else if (!(key && !*key))
  605.       if ((connection=connect_to_server(server_name,atoi(service)))
  606.            == NULL)  {
  607.      if (TRACE) fprintf (stderr,
  608.          "%sCan't open connection to %s via service %s.\n",
  609.          error_header, server_name, service);
  610.      free(names);
  611.      return HTLoadError(sink, 500, "Can't open connection to WAIS server");
  612.     }
  613.  
  614.     StrAllocCopy(wais_database,www_database);
  615.     HTUnEscape(wais_database);
  616.     
  617.     /* This below fixed size stuff is terrible */
  618.     request_message = (char*)s_malloc((size_t)MAX_MESSAGE_LEN * sizeof(char));
  619.     response_message = (char*)s_malloc((size_t)MAX_MESSAGE_LEN * sizeof(char));
  620.  
  621. /*    If keyword search is performed but there are no keywords,
  622. **    the user has followed a link to the index itself. It would be
  623. **    appropriate at this point to send him the .SRC file - how?
  624. */
  625.  
  626.     if (key && !*key) {                /* I N D E X */
  627.     
  628.     
  629.     HTStructured * target = HTML_new(anAnchor, format_out, sink);
  630.     
  631.     START(HTML_ISINDEX);
  632.  
  633.     /* If we have seen a source file for this database, use that:
  634.     */
  635.  
  636. #ifdef CACHING            /* old code ... do it this way now? */
  637.  
  638.     char filename[256];
  639.     FILE * fp;
  640.     sprintf(filename, "%s%s:%s:%s.html",
  641.         WAIS_CACHE_ROOT,
  642.         server_name, service, www_database);
  643.  
  644.     fp = fopen(filename, "r");    /* Have we found this already? */
  645.     if (TRACE) fprintf(stderr,
  646.         "WAISGate: Description of server %s %s.\n",
  647.         filename,
  648.         fp ? "exists already" : "does NOT exist!");
  649.  
  650.     if (fp) {
  651.         char c;
  652.         while((c=getc(fp))!=EOF) PUT(c);    /* Transfer file */
  653.         fclose(fp);
  654.     } else
  655. #endif
  656.     {
  657.         START(HTML_TITLE);
  658.         PUTS(wais_database);
  659.         PUTS(" index");
  660.         END(HTML_TITLE);
  661.         
  662.         START(HTML_H1);
  663.         PUTS(wais_database);
  664.         END(HTML_H1);
  665.         
  666.     }
  667.     PUTS("Specify search words.");
  668.     
  669.     END_TARGET;
  670.     FREE_TARGET;
  671.     
  672.     } else if (key) {                    /* S E A R C H */
  673.     char *p;
  674.     HTStructured * target;
  675.     
  676.     strncpy(keywords, key, MAX_KEYWORDS_LENGTH);
  677.     while(p=strchr(keywords, '+')) *p = ' ';
  678.     
  679.         /* Send advance title to get something fast to the other end */
  680.     
  681.     target = HTML_new(anAnchor, format_out, sink);
  682.     
  683.     START(HTML_ISINDEX);
  684.     START(HTML_TITLE);
  685.     PUTS(keywords);
  686.     PUTS(" (in ");
  687.     PUTS(wais_database);
  688.     PUTS(")");
  689.     END(HTML_TITLE);
  690.     
  691.     START(HTML_H1);
  692.     PUTS(keywords);
  693.     END(HTML_H1);
  694.  
  695.     request_buffer_length = MAX_MESSAGE_LEN; /* Amount left */
  696.     if (TRACE) fprintf(stderr, "WAISGate: Search for `%s' in `%s'\n",
  697.         keywords, wais_database);
  698.     if(NULL ==
  699.     generate_search_apdu(request_message + HEADER_LENGTH, 
  700.                 &request_buffer_length, 
  701.                 keywords, wais_database, NULL, MAXDOCS))
  702.     panic("request too large");
  703.     
  704.  
  705.     if(!interpret_message(request_message, 
  706.                 MAX_MESSAGE_LEN - request_buffer_length, 
  707.                 response_message,
  708.                 MAX_MESSAGE_LEN,
  709.                 connection,
  710.                 false    /* true verbose */
  711.                 )) {
  712.         panic("returned message too large");
  713.     
  714.         } else {    /* returned message ok */
  715.     
  716.         SearchResponseAPDU  *query_response = 0;
  717.         readSearchResponseAPDU(&query_response,
  718.             response_message + HEADER_LENGTH);
  719.         display_search_response(target, 
  720.             query_response, wais_database, keywords);
  721.         if (query_response->DatabaseDiagnosticRecords)
  722.         freeWAISSearchResponse(
  723.             query_response->DatabaseDiagnosticRecords);         
  724.         freeSearchResponseAPDU( query_response);
  725.     }    /* returned message not too large */
  726.     
  727.     END_TARGET;
  728.     FREE_TARGET;
  729.  
  730.     } else {            /* D O C U M E N T    F E T C H */
  731.     
  732.     HTFormat format_in;
  733.     HTStream * target;
  734.     long count;
  735.     any   doc_chunk;
  736.     any * docid = &doc_chunk;
  737.     if (TRACE) printf(
  738.         "WAISGate: Retrieve document id `%s' type `%s' length %ld\n",
  739.         docname, doctype, document_length);
  740.         
  741.     format_in = 
  742.       !strcmp(doctype, "WSRC") ? HTAtom_for("application/x-wais-source") :
  743.       !strcmp(doctype, "TEXT") ? HTAtom_for("text/plain") :
  744.       !strcmp(doctype, "GIF")  ? HTAtom_for("image/gif") :
  745.                             HTAtom_for("text/plain");
  746.  
  747.     target = HTStreamStack(format_in, format_out, sink, anAnchor);
  748.     if (!target) return HTLoadError(sink, 500,
  749.         "Can't convert format of WAIS document");
  750. /*    Decode hex or litteral format for document ID
  751. */    
  752.     WAIS_from_WWW(docid, docname);
  753.  
  754.     
  755. /*    Loop over slices of the document
  756. */    
  757.     for(count = 0; 
  758.         count * CHARS_PER_PAGE < document_length;
  759.         count++){
  760.       char *type = s_strdup(doctype);    /* Gets freed I guess */
  761.       request_buffer_length = MAX_MESSAGE_LEN; /* Amount left */
  762.       if (TRACE) fprintf(stderr, "HTWAIS: Slice number %ld\n", count);
  763.       if(0 ==
  764.           generate_retrieval_apdu(request_message + HEADER_LENGTH,
  765.             &request_buffer_length, 
  766.             docid, 
  767.             CT_byte,
  768.             count * CHARS_PER_PAGE,
  769.             MIN((count + 1) * CHARS_PER_PAGE,document_length),
  770.             type,
  771.             wais_database
  772.             ))
  773.         panic("request too long");
  774.       
  775.       /*    Actually do the transaction given by request_message */   
  776.       if(0 ==
  777.          interpret_message(request_message, 
  778.                    MAX_MESSAGE_LEN - request_buffer_length, 
  779.                    response_message,
  780.                    MAX_MESSAGE_LEN,
  781.                    connection,
  782.                    false /* true verbose */    
  783.                    ))
  784.         panic("Returned message too large");
  785.  
  786.       /*     Parse the result which came back into memory.
  787.       */
  788.       readSearchResponseAPDU(&retrieval_response, 
  789.                  response_message + HEADER_LENGTH);
  790.  
  791.       if(NULL == ((WAISSearchResponse *)
  792.           retrieval_response->DatabaseDiagnosticRecords)->Text){
  793.         /* display_search_response(target, retrieval_response,
  794.                     wais_database, keywords); */
  795.         PUTS("No text was returned!\n");
  796.         /* panic("No text was returned"); */
  797.       } else {
  798.       
  799.         output_text_record(target,
  800.            ((WAISSearchResponse *)
  801.             retrieval_response->DatabaseDiagnosticRecords)->Text[0],
  802.         false);
  803.       
  804.       } /* If text existed */
  805.       
  806.     }    /* Loop over slices */
  807.  
  808.     (*target->isa->end_document)(target);
  809.     (*target->isa->free)(target);
  810.  
  811.     free (docid->bytes);
  812.     
  813.     freeWAISSearchResponse( retrieval_response->DatabaseDiagnosticRecords); 
  814.     freeSearchResponseAPDU( retrieval_response);
  815.  
  816.     } /* If document rather than search */
  817.  
  818.  
  819.  
  820.  
  821. /*    (This postponed until later,  after a timeout:)
  822. */
  823.     if (connection) close_connection(connection);
  824.     if (wais_database) free(wais_database);
  825.     s_free(request_message);
  826.     s_free(response_message);
  827.  
  828.     free(names);
  829.     return HT_LOADED;
  830. }
  831.  
  832. PUBLIC HTProtocol HTWAIS = { "wais", HTLoadWAIS, NULL };
  833.  
  834.  
  835.